//
//  NSObject+Extension.h
//  TableDemo
//
//  Created by jutuo on 2020/3/19.
//  Copyright © 2020 jutuo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
NS_ASSUME_NONNULL_BEGIN

@interface NSObject (Extension)
// 是否为 <null>
- (BOOL)isNull;

#pragma mark - Sending messages with variable parameters
- (nullable id)performSelectorWithArgs:(SEL)sel, ...;
- (void)performSelectorWithArgs:(SEL)sel afterDelay:(NSTimeInterval)delay, ...;
- (nullable id)performSelectorWithArgsOnMainThread:(SEL)sel waitUntilDone:(BOOL)wait, ...;
- (nullable id)performSelectorWithArgs:(SEL)sel onThread:(NSThread *)thread waitUntilDone:(BOOL)wait, ...;
- (void)performSelectorWithArgsInBackground:(SEL)sel, ...;
- (void)performSelector:(SEL)sel afterDelay:(NSTimeInterval)delay;


#pragma mark - get propertys -
- (void)propertysBlock:(void(^)(NSString *propertyName,id propertyValue))propertys;

#pragma mark - Swap method (Swizzling)
///=============================================================================
/// @name Swap method (Swizzling)
///=============================================================================

/**
 Swap two instance method's implementation in one class. Dangerous, be careful.
 
 @param originalSel   Selector 1.
 @param newSel        Selector 2.
 @return              YES if swizzling succeed; otherwise, NO.
 */
+ (BOOL)swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel;


+ (BOOL)swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel class:(Class)cls;

/**
 Swap two class method's implementation in one class. Dangerous, be careful.
 
 @param originalSel   Selector 1.
 @param newSel        Selector 2.
 @return              YES if swizzling succeed; otherwise, NO.
 */
+ (BOOL)swizzleClassMethod:(SEL)originalSel with:(SEL)newSel;


#pragma mark - Associate value
///=============================================================================
/// @name Associate value
///=============================================================================

/**
 Associate one object to `self`, as if it was a strong property (strong, nonatomic).
 
 @param value   The object to associate.
 @param key     The pointer to get value from `self`.
 */
- (void)setAssociateValue:(nullable id)value withKey:(void *)key;

/**
 Associate one object to `self`, as if it was a weak property (week, nonatomic).
 
 @param value  The object to associate.
 @param key    The pointer to get value from `self`.
 */
- (void)setAssociateWeakValue:(nullable id)value withKey:(void *)key;

/**
 Get the associated value from `self`.
 
 @param key The pointer to get value from `self`.
 */
- (nullable id)getAssociatedValueForKey:(void *)key;

/**
 Remove all associated values.
 */
- (void)removeAssociatedValues;


#pragma mark - KVO Extension -
- (void)addObserverBlockForKeyPath:(NSString *)keyPath block:(void(^)(__weak id obj,id oldVal,id newVal))block;

- (void)removeObserverBlocksForKeyPath:(NSString*)keyPath;

- (void)removeAllObserverBlocks;
@end


@interface XYNSObjectKVOBlockTarget : NSObject
@property (nonatomic, copy) void (^block)(__weak id obj,id oldVal,id newVal);

- (id)initWithBlock:(void (^)(__weak id obj,id oldVal,id newVal))block;
@end
NS_ASSUME_NONNULL_END
